package com.ys.job.eth;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.ys.entity.WalletAddress;
import com.ys.entity.WalletDeposit;
import com.ys.entity.WalletScanBlock;
import com.ys.entity.block.Gather;
import com.ys.entity.block.eth.EthBlockEntity;
import com.ys.enu.CurrencyEnum;
import com.ys.service.WalletAddressServiceImap;
import com.ys.service.WalletDepositServiceImap;
import com.ys.service.WalletScanBlockServiceImap;
import com.ys.service.WalletWithdrawServiceImap;
import com.ys.service.wallet.WalletServicceContext;
import com.ys.service.wallet.base.IWalletService;
import com.ys.service.wallet.eth.EthService;
import com.ys.service.wallet.eth.EthWalletServiceBase;
import com.ys.util.HexUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.math.BigInteger;
import java.util.Date;
import java.util.List;

/**
 *  以太系定时任务
 *  以太坊冲币deposit扫描定时任务
 */
@Component
@Data
@Slf4j
public class EthDepositJob {

    @Autowired
    private WalletScanBlockServiceImap walletScanBlockServiceImap;
    @Autowired
    private EthWalletServiceBase ethWalletServiceBase;
    @Autowired
    private EthService ethService;

    @Autowired
    private WalletWithdrawServiceImap walletWithdrawServiceImap;
    @Autowired
    private WalletServicceContext walletServicceContext;
    @Autowired
    private WalletAddressServiceImap walletAddressServiceImap;

    @Autowired
    private WalletDepositServiceImap walletDepositServiceImap;

    /**
     * 充币，扫描以太坊block
     */
    @Scheduled(cron = "1 * * * * ?")
    public void ethDeposite() throws Exception {
        log.info("冲币扫描blcok start");
        while(true){
            WalletScanBlock wsb=new WalletScanBlock();
            wsb.setCurrency(CurrencyEnum.ETH.getCurrency());
            EntityWrapper<WalletScanBlock> entity=new EntityWrapper(wsb);

            WalletScanBlock wsbResult=walletScanBlockServiceImap.selectOne(entity);

            if(wsbResult==null){
                log.warn("定时任务：ethDeposite结束，可用任务队列为空。wsb="+ JSONUtil.toJsonStr(wsb));
                return ;
            }
            log.info("区块号：num="+wsbResult.getBlockNum());
            EthBlockEntity b= (EthBlockEntity) ethWalletServiceBase.queryBlockByNum(wsbResult.getBlockNum(),new EthBlockEntity());
            if(b==null){
                log.warn("区块信息查询为空");
                break;
            }
            log.info("block信息："+JSONUtil.toJsonStr(b));
            if(CollUtil.isNotEmpty(b.getTransactions()))
                ethService.dealBlock(b.getTransactions());
            wsb.setId(wsbResult.getId());
            wsb.setBlockNum(wsbResult.getBlockNum()+1);
            wsb.setEditDate(new Date());
            walletScanBlockServiceImap.updateById(wsb);
        }
        log.info("充币扫描blcok end");
    }

    /**
     *
     * 更新冲提交易状态
     */
    @Scheduled(cron = "30 * * * * ?")
    public void confirmDepositeWithdrawStatus(){
        /**查询连上的最新区块数**/
        String blockNum=ethWalletServiceBase.mostRecentBlockNumber();

        if(StrUtil.isBlank(blockNum)){
            log.warn("Eth确认充值查询块号失败！");
            return ;
        }
        ethService.updateDepositWithdrawStatus(HexUtil.hexToInteger(blockNum));
    }



    /**
     * 归集
     */
    @Scheduled(cron = "33 * * * * ?")
    public void gatherBalance(){
        log.info("归集Job start");
        EntityWrapper<WalletDeposit> ew=new EntityWrapper<>();
        ew.isNotNull("balance");
        ew.ge("status",20);
        ew.eq("gatherStatus",0);
        List<WalletDeposit> list=walletDepositServiceImap.selectList(ew);
        if(CollUtil.isEmpty(list)){
            log.info("归集任务为空");
            return ;
        }

        for(WalletDeposit walletDeposit:list){
            IWalletService walletService=walletServicceContext.getWalletRPC(walletDeposit.getCurrency());
            BigInteger balance=walletService.queryBalanceByAddress(walletDeposit.getDepositToAddress());
            if(balance==null || balance.compareTo(new BigInteger("0"))<=0){
                log.warn("归集金额不对：walletDeposit"+ JSONUtil.toJsonStr(walletDeposit));
                continue;
            }
            CurrencyEnum currency=CurrencyEnum.parseCurrency(walletDeposit.getCurrency());
            if(balance.compareTo(currency.getGatherMaxBalance())<0){
                log.info("钱包余额balanc="+balance+",小于归集阈值：maxBalanc="+currency.getGatherMaxBalance());
                continue;
            }

            //状态改为归集中

            WalletDeposit updateGatherStaus=new WalletDeposit();
            updateGatherStaus.setId(walletDeposit.getId());
            updateGatherStaus.setGatherStatus(10);
            walletDepositServiceImap.updateById(updateGatherStaus);

            Gather gather=new Gather();
            gather.setFrom(walletDeposit.getDepositToAddress());
            gather.setAmount(walletDeposit.getBalance());
            gather.setCurrency(walletDeposit.getCurrency());
            gather.setCurrencyChainType(walletDeposit.getCurrencyChainType());

            EntityWrapper<WalletAddress> walletAddressEw=new EntityWrapper<>();
            walletAddressEw.eq("adress",gather.getFrom());
            walletAddressEw.eq("currency",gather.getCurrency());
            WalletAddress walletAddress= walletAddressServiceImap.selectOne(walletAddressEw);
            if(walletAddress==null){
                log.warn("归集查询钱包密码错误：gather="+JSONUtil.toJsonStr(gather));
                continue;
            }

            String salt=walletAddress.getSalt();
            String password=walletAddress.getPassword();
            gather.setPassword(SecureUtil.des(salt.getBytes()).decryptStrFromBase64(password));
            /**归集开始**/
            String txHash=walletService.sendGatherTransation(gather);
            if(StrUtil.isBlank(txHash)){
                log.warn("归集失败：gather="+JSONUtil.toJsonStr(gather));
                continue;
            }
            /**归集结束**/
            //插入归集表
            log.info("归集hash="+txHash);

            /**更新归集状态为已完成**/
            updateGatherStaus.setGatherStatus(20);
            walletDepositServiceImap.updateById(updateGatherStaus);
        }

        log.info("归集job end");
    }

    /**
     * 冲币后更新钱包余额
     */
    @Scheduled(cron = "25 * * * * ?")
    public void updateDepsiteBalance(){
        log.info("冲币后更新钱包余额任务开始 start");
        EntityWrapper<WalletDeposit> ew=new EntityWrapper<>();
        ew.isNull("balance");
        ew.ge("status",20);
        ew.eq("currencyChainType",CurrencyEnum.ETH.currencyChainType);
        List<WalletDeposit> list=walletDepositServiceImap.selectList(ew);
        if(CollUtil.isEmpty(list)){
            log.info("冲币更新地址余额任务为空");
            return ;
        }

        for(WalletDeposit walletDeposit:list){
            IWalletService walletService=walletServicceContext.getWalletRPC(walletDeposit.getCurrency());
            BigInteger balance=walletService.queryBalanceByAddress(walletDeposit.getDepositToAddress());
            if(balance==null || balance.compareTo(new BigInteger("0"))<=0){
                log.warn("冲币记录查询的余额为零：walletDeposit"+ JSONUtil.toJsonStr(walletDeposit));
                continue;
            }

            WalletDeposit updateBalance=new WalletDeposit();
            updateBalance.setId(walletDeposit.getId());
            updateBalance.setBalance(balance);
            updateBalance.setGatherStatus(0);
            walletDepositServiceImap.updateById(updateBalance);
        }

        log.info("冲币后更新钱包余额任务开始 end");
    }

}